package netty.rpc.framework.core.netty.consumer;

import lombok.extern.slf4j.Slf4j;
import netty.rpc.framework.core.netty.transport.protocol.RPCMessage;
import netty.rpc.framework.core.netty.transport.protocol.RPCRequest;
import netty.rpc.framework.core.netty.transport.protocol.RPCResponse;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 客户端生成PRC调用的代理对象，并对请求参数进行封装并发送
 * @param <T> 服务接口类型
 */
@Slf4j
public class ConsumerProxy<T> implements InvocationHandler {

    //请求时自动生成序号
    private static AtomicInteger requestInteger = new AtomicInteger(1);

    private ClientTransport clientTransport;

    public ConsumerProxy(ClientTransport clientTransport) {
        this.clientTransport = clientTransport;
    }

    /**
     * 通过类的class对象生成客户端代理对象
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public  T getServiceBean( final  Class<T> clazz){
        //return Proxy object
        return (T)Proxy.newProxyInstance(
                clazz.getClassLoader(),
                new Class[]{clazz},
                this
        );
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //生成RPCRequest对像
        int requestId = requestInteger.getAndIncrement();
        if(requestId == Integer.MAX_VALUE-1){
            requestInteger.set(1);
        }
        if(args == null){
            args = new Object[0];
        }
        Class<?>[] paramsTypes = new Class[args.length];
        for(int i = 0; i < args.length; i++){
            Class<?> clazz = args[i].getClass();
            paramsTypes[i] = clazz;
        }

        RPCRequest rpcRequest = RPCRequest.builder()
                .requestId(requestId)
                .interfaceName(method.getDeclaringClass().getCanonicalName())
                .methodName(method.getName())
                .paramsTypes(paramsTypes)
                .paramsValue(args)
                .build();

        //利用地址信息 send rpcRequest
        CompletableFuture<RPCResponse> resultFuture =
                clientTransport.sendRPCRequest(rpcRequest);
        //---
        //接受响应对象
        RPCResponse response = resultFuture.get();
        log.info("response"+response.toString());
        if(response.getCode() != 200){
            throw new RuntimeException("RPC调用失败！！！");
        }
        return response.getData();
    }
}
